@radixdlt/account
Account related APIs for Radix.
Wallet
We have a WalletT
type being a hierchal deterministic wallet (explained by Ledger Acadamy and on BitcoinWiki) capable of deriving all "account"s you will need.
The trailing T in WalletT
is a suffix we use for all type
s (we don't use TypeScript class
es at all). We reserve the Wallet
name as a "namespaces" for our types, providing static-like factory/constructor methods, e.g. Wallet.create
(N.B. the lack of trailing T). This decision was taken since we believe you will more often use the namespace Wallet.create
than you have to declare the type WalletT
.
Here follows the generation of a new mnemonic and the creation of a wallet, via the saving of a keystore.
Simple wallet creation
This outlines the most convenient wallet creation flow using byEncryptingMnemonicAndSavingKeystore
.
import { Mnemonic, Strength, Language } from '@radixdlt/account'
const mnemonic = Mnemonic.generateNew()
const keystoreEncryptionPassword = confirmPasswordTextField.value()
import { PathLike, promises as fsPromises } from 'fs'
const saveKeystoreOnDisk = (keystore: KeystoreT): Promise<void> => {
const filePath = 'SOME/SUITABLE/PATH/keystore.json'
const json = JSON.stringify(keystore, null, '\t')
return fsPromises.writeFile(filePath, json)
}
const walletResult = await Wallet.byEncryptingMnemonicAndSavingKeystore({
mnemonic,
password: keystoreEncryptionPassword,
save: saveKeystoreOnDisk,
})
if (walletResult.isErr()) {
console.log(`🤷♂️ Failed to create wallet: ${walletResult.error}`)
} else {
const wallet = walletResult.value
}
1️⃣: The keystoreEncryptionPassword
will be needed everytime the user re-opens the wallet app after having terminated it. It's used to decrypt the encrypted hdMasterSeed
. Remember, the keystore is just a JSON file containing an encrypted ciphertext, and metadata about the encryption used to derive said cihpertext. The ciphertext itself is the BIP39 "seed", not the entropy/mnemonic itself.
2️⃣ Read more about Result
/ ResultAsync
Alternative wallet creation
Alternatively you can use a flow where you have a bit more control. This is basically exactly what Wallet.byEncryptingMnemonicAndSavingKeystore
above does.
const mnemonic = Mnemonic.generateNew()
const masterSeed = HDMasterSeed.fromMnemonic({ mnemonic })
const keystoreEncryptionPassword = confirmPasswordTextField.value()
const walletResult = await Keystore.encryptSecret({
secret: masterSeed.seed,
password,
})
.map((keystore) => ({ keystore, filePath: keystorePath }))
.andThen((keystore) => {
})
.map((keystore) => ({ keystore, password: keystoreEncryptionPassword }))
.andThen(Wallet.fromKeystore)
if (walletResult.isErr()) {
console.log(`🤷♂️ Failed to create wallet: ${walletResult.error}`)
} else {
const wallet = walletResult.value
}
Open wallet (app start)
import { Keystore } from "./keystore";
import { PathLike, promises as fsPromises } from 'fs'
const keystoreEncryptionPassword = passwordTextField.value()
const loadKeystoreOnDisk = (): Promise<KeystoreT> => {
const filePath = 'SOME/SUITABLE/PATH/keystore.json'
return fsPromises.readFile(filePath)
.then(buffer => Keystore.fromBuffer(buffer))
}
const walletResult = await Wallet.byLoadingAndDecryptingKeystore({
password: keystoreEncryptionPassword,
load: loadKeystoreOnDisk
})
if (walletResult.isErr()) {
console.log(`🤷♂️ Failed to create wallet: ${walletResult.error}`)
} else {
const wallet = walletResult.value
}